home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 4
/
Aminet 4 - November 1994.iso
/
aminet
/
comm
/
net
/
plip38src.lha
/
plip
/
plip.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-06-27
|
27KB
|
1,215 lines
/*
* PLIP.device - Parallel Line Internet Protocol
*
* A SANA2 networking device driver for two Amigas connected via their
* parallel ports.
*
* By Oliver Wagner with a little assistance of Michael Balzer.
* Copyright (c) 1993-1994 Oliver Wagner and Michael Balzer.
*
*/
#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/cia.h>
#include <proto/misc.h>
#include <proto/utility.h>
#include <proto/timer.h>
#include <devices/sana2.h>
#include <hardware/cia.h>
#include <resources/misc.h>
#include <exec/memory.h>
#include <dos/dostags.h>
#include <string.h>
#define min __builtin_min
#define max __builtin_max
#define abs __builtin_abs
#define SERVER_TASK "PLIP Server Task"
#define PLIP_MTU 8192
#define PLIP_DEFMTU 1024
#define PLIP_BPS 15000
#define PLIP_HWTYPE 13
#define PLIP_RETRIES 63
LONG plip_bps = PLIP_BPS;
LONG plip_mtu = PLIP_DEFMTU;
LONG plip_retries = PLIP_RETRIES;
#define ios2_Error ios2_Req.io_Error
#define ios2_Flags ios2_Req.io_Flags
#define PKTFRAMESIZE 8
struct intdata {
/*0*/ USHORT mode,pad1;
/*4*/ ULONG recsig; /* signals for receive */
/*8*/ struct Task *sigtask; /* device task to signal */
/*12*/ struct ExecBase *SysBase; /* local sysbase copy for interrupt */
};
struct sendframe {
long sync;
short size;
unsigned short crc;
long pkt;
unsigned char data[PLIP_MTU];
} sendframe, receiveframe;
#define SYNCBYTE 0x42
struct trackrec {
struct MinNode n;
ULONG packettype;
struct Sana2PacketTypeStats s2ps;
};
struct MyDev {
struct Library l;
UBYTE flags, pad;
APTR seglist;
};
struct BufRoutines {
long __asm (*CopyToBuff)(register __a0 void*,register __a1 void*,register __d0 long);
long __asm (*CopyFromBuff)(register __a0 void*,register __a1 void*,register __d0 long);
};
extern far volatile struct CIA ciaa,ciab;
__aligned struct Library *MiscBase, *CIAABase;
struct Library *UtilityBase, *TimerBase;
struct DosLibrary *DOSBase;
struct ExecBase *SysBase;
static __aligned struct intdata intdata;
static __aligned struct Interrupt intstruc;
static long allocflags;
static struct MsgPort *serverport, *timerport;
static __aligned struct Sana2DeviceStats devstats; /* device stats */
static __aligned struct timerequest treq;
static __aligned struct List readlist, writelist, eventlist, readorphanlist, tracklist;
static __aligned struct SignalSemaphore eventlistsem, writelistsem, tracklistsem;
#define FLG_CLIENT 1 /* client mode */
#define FLG_EXCLUSIVE 2 /* current opener is exclusive */
#define FLG_NOTCONFIGURED 4 /* not configured */
#define FLG_OFFLINE 8
#define ISOFFLINE (devflags & (FLG_OFFLINE | FLG_NOTCONFIGURED))
static long devflags = FLG_NOTCONFIGURED; /* current flags */
#define IM_CLIENT 1 /* client mode */
#define IM_SEND 2 /* sending pkt */
#define IM_REC 4 /* receiving */
#define IM_GETHEADER 8 /* got 1 char */
#define IM_BUFF2 16 /* just filled second buffer */
#define IM_RXERROR 32 /* receive error */
#define IM_GOTSYNC 64
extern void intcode(void);
extern void __asm settimeout(register __d0 ULONG timeout);
extern void __asm parinit(register __d0 int);
extern long __asm testbusy(void), testpout(void);
extern void __asm setbusy(register __d0 long), setpout(register __d0 long);
extern long __asm waitinputtoggle(void);
extern void __asm setciaoutput(void);
extern void __asm outputtoggle(void);
extern void __asm sampleinput(void);
extern USHORT __asm CRC16( register __a0 UBYTE *, register __d0 SHORT );
/***********************************************************
* TRACKTYPE support
*/
static struct trackrec * __inline findtracktype( ULONG type )
{
struct trackrec * tr = ( struct trackrec * ) tracklist.lh_Head;
while( tr->n.mln_Succ )
{
if( tr->packettype == type )
return( tr );
tr = ( struct trackrec * ) tr->n.mln_Succ;
}
return( NULL );
}
static int addtracktype( ULONG type )
{
struct trackrec *tr;
ObtainSemaphore( &tracklistsem );
tr = findtracktype( type );
if( tr )
{
ReleaseSemaphore( &tracklistsem );
return( -1 );
}
else
{
tr = AllocMem( sizeof( *tr ), MEMF_CLEAR );
if( !tr )
{
ReleaseSemaphore( &tracklistsem );
return( -2 );
}
tr->packettype = type;
AddTail( &tracklist, ( struct Node * ) tr );
}
ReleaseSemaphore( &tracklistsem );
return( 0 );
}
static int remtracktype( ULONG type )
{
struct trackrec *tr;
ObtainSemaphore( &tracklistsem );
tr = findtracktype( type );
if( tr )
{
Remove( ( struct Node * ) tr );
FreeMem( tr, sizeof( *tr ) );
ReleaseSemaphore( &tracklistsem );
return( 0 );
}
ReleaseSemaphore( &tracklistsem );
return( -1 );
}
static void __inline dotracktype( ULONG type, ULONG ps, ULONG pr, ULONG bs, ULONG br, ULONG pd )
{
struct trackrec * tr;
ObtainSemaphoreShared( &tracklistsem );
tr = findtracktype( type );
if( tr )
{
tr->s2ps.PacketsSent += ps;
tr->s2ps.PacketsReceived += pr;
tr->s2ps.BytesSent += bs;
tr->s2ps.BytesReceived += br;
tr->s2ps.PacketsDropped += pd;
}
ReleaseSemaphore( &tracklistsem );
}
static int gettrackrec( ULONG type, APTR info )
{
struct trackrec * tr;
ObtainSemaphoreShared( &tracklistsem );
tr = findtracktype( type );
if( tr )
{
memcpy( info, &tr->s2ps, sizeof( tr->s2ps ) );
ReleaseSemaphore( &tracklistsem );
return( 0 );
}
ReleaseSemaphore( &tracklistsem );
return( -1 );
}
/***********************************************************
* CIA Zugriff
*/
static void __inline writecia( unsigned char val )
{
ciaa.ciaprb = val;
}
static unsigned char __inline readciabyte( void )
{
return( ciaa.ciaprb );
}
/***********************************************************
* Event-Handling: Alle Event-Requests zurückschicken,
* die auf das eingetretene Ereignis passen.
*/
void DoEvent( long event )
{
struct IOSana2Req *ior, *ior2;
ObtainSemaphore( &eventlistsem );
for( ior = (struct IOSana2Req *) eventlist.lh_Head;
ior2 = (struct IOSana2Req *) ior->ios2_Req.io_Message.mn_Node.ln_Succ;
ior = ior2 )
{
if( ior->ios2_WireError & event )
{
Remove( ior );
ReplyMsg( ior );
}
}
ReleaseSemaphore( &eventlistsem );
}
/***********************************************************
* Interrupt Support
*/
static void __inline disableint( void )
{
AbleICR( CIAABase, CIAICRF_FLG );
}
static void __inline enableint( void )
{
AbleICR( CIAABase, CIAICRF_FLG | CIAICRF_SETCLR );
}
static long setupint( void )
{
MiscBase = OpenResource( "misc.resource" );
CIAABase = OpenResource( "ciaa.resource" );
/* Parallel-Port allokieren */
if( AllocMiscResource( MR_PARALLELPORT, "plip.device" ) ) return 1;
allocflags |= 1;
if( AllocMiscResource( MR_PARALLELBITS, "plip.device" ) ) return 2;
allocflags |= 2;
intstruc.is_Node.ln_Type = NT_INTERRUPT;
intstruc.is_Node.ln_Pri = 0;
intstruc.is_Node.ln_Name = "PLIP PORTS Interrupt";
intstruc.is_Data = &intdata;
intstruc.is_Code = intcode;
/* Interrupt einfügen */
Disable();
{
/* Parallel-Port initialisieren */
parinit( intdata.mode & IM_CLIENT );
if( AddICRVector( CIAABase, CIAICRB_FLG, &intstruc ) )
{
Enable();
return 3;
}
allocflags |= 4;
}
Enable();
enableint();
return 0;
}
static void cleanupint( void )
{
if( allocflags & 4 ) RemICRVector( CIAABase, CIAICRB_FLG, &intstruc );
if( allocflags & 2 ) FreeMiscResource( MR_PARALLELBITS );
if( allocflags & 1 ) FreeMiscResource( MR_PARALLELPORT );
allocflags = 0;
}
/***********************************************************
* WRITE
*
* Der Leser steuert über POUT (bzw. BUSY) die Übertragung.
* Init: Schreiber schreibt Byte 1, was beim Leser einen Interrupt
* auslöst. Der Leser quittiert den Empfang jedes Bytes mit einem Wechsel
* der Handshake-Leitung, der Schreiber zeigt dem Leser durch Wechsel
* der anderen Handshake-Leitung an, wenn ein Byte bereit steht.
*
* Um Deadlocks zu vermeiden (race condition) wird _einmal_ _vor_ der
* Übertragung der Zustand des Handshakes eingelesen und dann immer
* nur noch ohne vorherigen Lesezugriff auf den Wechsel gewartet.
*/
/* Falls beim Warten auf die Lesebestätigung ein Timeout passiert: */
#define ABORTWRITE { \
DoEvent( S2EVENT_ERROR | S2EVENT_TX ); \
intdata.mode &= ~IM_SEND; \
parinit( intdata.mode & IM_CLIENT ); \
enableint(); \
return(-1); }
static long procwrite( unsigned char *data, long size )
{
/* Init */
disableint();
setciaoutput();
/* aktuellen Stand der Handshake-Leitung samplen */
sampleinput();
/* Übertragung anstoßen */
writecia( *data++ );
while( --size )
{
if( !waitinputtoggle() ) ABORTWRITE;
writecia( *data++ );
outputtoggle();
}
/* Bestätigung für letztes Byte abwarten */
if( !waitinputtoggle() ) ABORTWRITE;
/* Ok. */
intdata.mode &= ~IM_SEND;
parinit( intdata.mode & IM_CLIENT );
enableint();
devstats.PacketsSent++;
return 0;
}
/***********************************************************
* READ
*
* Wird vom Interrupt aus angestoßen.
*/
/* Falls beim Warten auf das nächste Byte ein Timeout passiert: */
#define ABORTREAD { \
devstats.BadData++; \
DoEvent( S2EVENT_ERROR | S2EVENT_RX ); \
intdata.mode &= ~IM_REC; \
parinit( intdata.mode & IM_CLIENT ); \
enableint(); \
return; }
static void procread( void )
{
unsigned short crc;
short len;
int l;
long bufferror,pkttyp;
struct IOSana2Req *got, *ro;
unsigned char *d, ch;
/* Init */
disableint();
sampleinput();
/* SYNC? */
if( readciabyte() != 0x42 ) ABORTREAD;
/* restliche SYNC-Bytes überlesen */
for(;;)
{
outputtoggle();
if( !waitinputtoggle() ) ABORTREAD;
if( (ch = readciabyte()) != 0x42 )
break;
}
/* Größe des Packets einlesen */
d = (unsigned char *) &receiveframe.size;
*d++ = ch;
outputtoggle();
if( !waitinputtoggle() ) ABORTREAD;
*d++ = readciabyte();
outputtoggle();
/* Packetgröße sinnvoll? */
len = receiveframe.size;
if( len < 6 || len > plip_mtu+6 ) ABORTREAD;
/* len Bytes einlesen */
while( len-- )
{
if( !waitinputtoggle() ) ABORTREAD;
*d++ = readciabyte();
outputtoggle();
}
/* fertig mit Lesen */
intdata.mode &= ~IM_REC;
/* Exit */
parinit( intdata.mode & IM_CLIENT );
enableint();
/* CRC check */
pkttyp = receiveframe.pkt;
l = receiveframe.size - 6;
d = receiveframe.data;
crc = CRC16( d, l );
if( crc == receiveframe.crc )
{
/* CRC OK! */
devstats.PacketsReceived++;
dotracktype( pkttyp, 0, 1, 0, l, 0 );
for( got = (struct IOSana2Req *) readlist.lh_Head;
got && got->ios2_Req.io_Message.mn_Node.ln_Succ;
got = (struct IOSana2Req *) got->ios2_Req.io_Message.mn_Node.ln_Succ )
{
if( got->ios2_PacketType == pkttyp )
{
/* Hurra, der will's haben! */
Remove( got );
/* Daten kopieren */
bufferror = ((struct BufRoutines *) got->ios2_BufferManagement)
-> CopyToBuff( got->ios2_Data, receiveframe.data, receiveframe.size - 6 );
/* Fehler? */
if( !bufferror )
{
got->ios2_Error = S2ERR_SOFTWARE;
got->ios2_WireError = S2WERR_BUFF_ERROR;
}
else
{
got->ios2_Error = got->ios2_WireError = 0;
}
/* Request befriedigen */
got->ios2_Flags = 0;
got->ios2_SrcAddr[0] = (devflags & FLG_CLIENT) ? 0 : (1<<7);
got->ios2_DstAddr[0] = (devflags & FLG_CLIENT) ? (1<<7) : 0 ;
got->ios2_DataLength = receiveframe.size - 6;
ReplyMsg( got );
/* und 'raus */
got=0;
break;
}
}
}
else
{
/* CRC ERROR! */
/* Clients Bescheid sagen, daß Müll ankam */
DoEvent( S2EVENT_ERROR | S2EVENT_RX );
got = 0;
devstats.BadData++;
}
if( got )
{
/* Hm... wir haben ein Packet bekommen, das keiner haben will... */
devstats.UnknownTypesReceived++;
/* ...aber vielleicht ist da ja jemand, der genau solche Packets auffängt: */
if( ro = (struct IOSana2Req *) RemHead( &readorphanlist ) )
{
/* Packet komplett kopieren */
bufferror = ((struct BufRoutines *) ro->ios2_BufferManagement)
-> CopyToBuff( ro->ios2_Data, &receiveframe.pkt, receiveframe.size - 2 );
/* Fehler? */
if( !bufferror )
{
ro->ios2_Error = S2ERR_SOFTWARE;
ro->ios2_WireError = S2WERR_BUFF_ERROR;
}
else
{
ro->ios2_Error = ro->ios2_WireError = 0;
}
/* Request befriedigen */
ro->ios2_Flags = 0;
ro->ios2_SrcAddr[0] = (devflags & FLG_CLIENT) ? 0 : (1<<7);
ro->ios2_DstAddr[0] = (devflags & FLG_CLIENT) ? (1<<7) : 0 ;
ro->ios2_DataLength = receiveframe.size - 2;
ReplyMsg( ro );
}
/* Noe, also entsorgen */
dotracktype( pkttyp, 0, 0, 0, 0, 1 );
}
}
/***********************************************************
* READARGS - reads ENV:PLIP
*/
static void __saveds readargs( void )
{
struct RDArgs *rda;
struct args {
ULONG *timeout;
LONG *priority;
ULONG *mtu;
ULONG *bps;
ULONG *retries;
} args = { 0 };
BPTR plipvar = Open( "ENV:SANA2/PLIP.config", MODE_OLDFILE );
BPTR oldinput, infowin, oldoutput;
infowin = Open( "con://320/128/PLIP V38.11/NOSIZE/INACTIVE", MODE_NEWFILE );
if( infowin )
{
FPrintf( infowin,
"\x1b[0 p\n"
"\x1b[1mPLIP V38.11\x1b[0m (" __DATE__ " " __TIME__ ")\n"
"by \x1b[3mOliver Wagner\x1b[0m & \x1b[3mMichael Balzer\x1b[0m\n"
"Freeware -- see manual!\n\n" );
}
if( !plipvar )
goto xit;
oldinput = SelectInput( plipvar );
rda = ReadArgs( "TIMEOUT/K/N,PRIORITY=PRI/K/N,MTU/K/N,BPS/K/N,RETRIES/K/N" , (LONG *)&args, NULL );
if(rda)
{
if(args.timeout)
{
settimeout( *args.timeout );
if( infowin ) FPrintf(infowin, " Timeout.: %lx/%ld\n", *args.timeout, *args.timeout);
}
if(args.priority)
{
SetTaskPri( FindTask(SERVER_TASK), *args.priority);
if( infowin ) FPrintf(infowin, " Priority: %ld\n", *args.priority);
}
if( args.mtu )
{
if( *args.mtu <= PLIP_MTU )
{
plip_mtu = *args.mtu;
if( infowin ) FPrintf(infowin, " MTU: %ld\n", *args.mtu);
}
}
if( args.bps )
{
plip_bps = *args.bps;
if( infowin ) FPrintf(infowin, " BPS: %ld\n", *args.bps);
}
if( args.retries )
{
if( *args.retries <= 127 )
{
plip_retries = *args.retries;
if( infowin ) FPrintf(infowin, " Max Retries: %ld\n", *args.retries);
}
}
FreeArgs( rda );
}
else if(infowin)
{
oldoutput = SelectOutput( infowin );
PrintFault( IoErr(), "\x07 PLIP");
SelectOutput( oldoutput );
}
Close( SelectInput( oldinput ));
xit:
/* Wake up Main server */
Signal( intdata.sigtask, SIGBREAKF_CTRL_E );
if( infowin )
{
Delay( 10*50 );
Close( infowin );
}
}
/***********************************************************
* MAINLOOP - Device Dispatcher
*/
static void __saveds servertask( void )
{
long portsig, s, timersig;
struct IOSana2Req *currentwrite = 0, *got, *nextwrite;
long timerqueued = 0, readstart = 0x42, bufferror;
/*
* Setup
*/
s = AllocSignal( -1 );
intdata.recsig = 1L << s;
serverport = CreateMsgPort();
timerport = CreateMsgPort();
portsig = 1 << serverport->mp_SigBit;
timersig = 1 << timerport->mp_SigBit;
NewList( &readlist );
NewList( &writelist );
NewList( &eventlist );
NewList( &readorphanlist );
NewList( &tracklist );
InitSemaphore( &eventlistsem );
InitSemaphore( &writelistsem );
InitSemaphore( &tracklistsem );
treq.tr_node.io_Message.mn_ReplyPort = timerport;
OpenDevice( "timer.device", UNIT_VBLANK, &treq, 0 );
TimerBase = (struct Library *) treq.tr_node.io_Device;
GetSysTime( &devstats.LastStart );
CreateNewProcTags(
NP_Entry, readargs,
NP_Name, "PLIP Arg Parser Process",
NP_Priority, 5,
NP_WindowPtr, -1,
TAG_DONE
);
/* Wait for reply from Arg Parser */
Wait( SIGBREAKF_CTRL_E );
for(;;)
{
/* Wir lassen uns regelmäßig vom timer.device aufwecken, damit
* keine Senderequests liegen bleiben, wenn wir nicht sofort
* die Leitung bekommen können
*/
if( !timerqueued )
{
treq.tr_time.tv_secs = 2 + (devflags & FLG_CLIENT);
treq.tr_time.tv_micro = 0;
treq.tr_node.io_Command = TR_ADDREQUEST;
SendIO( &treq );
timerqueued = 1;
}
s = Wait( intdata.recsig | portsig | timersig );
if( s & intdata.recsig )
{
/* Interrupt: Packet empfangen */
procread();
}
if( s & timersig )
{
/* Aufwecksignal */
AbortIO( &treq );
WaitIO( &treq );
timerqueued = 0;
}
if( s & portsig )
{
/* Kommandos (Requests) entgegennehmen */
while( got = (struct IOSana2Req *) GetMsg( serverport ) )
{
if( got->ios2_Req.io_Command == CMD_READ )
AddTail( &readlist, got );
else if( got->ios2_Req.io_Command == S2_READORPHAN )
AddTail( &readorphanlist, got );
else
{
ObtainSemaphore( &writelistsem );
AddTail( &writelist, got );
ReleaseSemaphore( &writelistsem );
}
}
}
/*
* So, Signale alle erledigt; haben wir 'was zu schreiben?
*/
ObtainSemaphore( &writelistsem );
for( currentwrite = (struct IOSana2Req *) writelist.lh_Head;
nextwrite = (struct IOSana2Req *) currentwrite->ios2_Req.io_Message.mn_Node.ln_Succ;
currentwrite = nextwrite )
{
/* Inzwischen ein Read-Interrupt? */
if( SetSignal(0,0) & intdata.recsig) break;
/* Arbitration */
if( devflags & FLG_CLIENT )
{
/* Leitung frei? */
if( !testbusy() )
break; /* später nochmal versuchen */
/* Sende-Status setzen */
setpout( 1 );
/* Leitung immer noch frei? */
if( !testbusy() )
{
setpout( 0 );
break; /* später nochmal versuchen */
}
}
else
{
/* Leitung frei? */
if( testpout() )
break; /* später nochmal versuchen */
/* Sende-Status setzen */
setbusy( 0 );
/* Leitung immer noch frei? */
if( testpout() )
{
/*setbusy( 1 );*/
break; /* später nochmal versuchen */
}
}
/* Gut, wir können beginnen zu senden */
/* Daten kopieren */
bufferror = ((struct BufRoutines *) currentwrite->ios2_BufferManagement)
-> CopyFromBuff( sendframe.data, currentwrite->ios2_Data, currentwrite->ios2_DataLength );
/* Fehler? */
if( !bufferror )
{
currentwrite->ios2_Error = S2ERR_SOFTWARE;
currentwrite->ios2_WireError = S2WERR_BUFF_ERROR;
Remove( currentwrite );
ReplyMsg( currentwrite );
continue;
/* weiter mit nächstem Write-Req */
}
/* Packet-Header füllen */
sendframe.sync = 0x42424242;
sendframe.pkt = currentwrite->ios2_PacketType;
sendframe.size = currentwrite->ios2_DataLength + 6;
/* CRC berechnen und einsetzen */
{
int l = currentwrite->ios2_DataLength;
unsigned char *d = sendframe.data;
unsigned short crc = 0;
crc = CRC16( d, l );
sendframe.crc = crc;
}
/* Packet Senden */
readstart = procwrite( (char *) &sendframe, sendframe.size + 6 );
if( !readstart )
{
/* Packet erfolgreich gesendet */
dotracktype( sendframe.pkt, 1, 0, currentwrite->ios2_DataLength, 0, 0 );
currentwrite->ios2_Error = currentwrite->ios2_WireError = 0;
Remove( currentwrite );
ReplyMsg( currentwrite );
}
else
{
/* Fehler; WriteRetryCounter erhöhen */
if( ( currentwrite->ios2_Error++ ) > plip_retries )
{
/* Maximale Fehleranzahl erreicht */
currentwrite->ios2_Error = S2ERR_BAD_STATE;
currentwrite->ios2_WireError = S2WERR_GENERIC_ERROR;
Remove( currentwrite );
ReplyMsg( currentwrite );
}
break;
}
}
ReleaseSemaphore( &writelistsem );
/* Alle Signale bearbeitet */
}
}
/************************************************************
* DEVICE-Management und -Support
*/
long __asm __saveds DevOpen( register __a1 struct IOSana2Req *ior,
register __d0 long unit, register __d1 long flags,
register __a6 struct MyDev *devnode )
{
struct TagItem *ti;
struct BufRoutines *br;
devnode->l.lib_OpenCnt++; /* Expunge-Schutz */
if( unit < 0 || unit > 1 )
{
devnode->l.lib_OpenCnt--;
ior->ios2_Req.io_Error = -1;
ior->ios2_Req.io_Device = (struct Device *) -1;
return( -1 );
/* openfailed */
}
/* already open? */
if( devnode->l.lib_OpenCnt > 1 )
{
if( (unit && !(devflags & FLG_CLIENT)) ||
(flags & SANA2OPF_MINE) )
{
/* busy/open */
devnode->l.lib_OpenCnt--;
ior->ios2_Req.io_Error = -1;
ior->ios2_Req.io_Device = (struct Device *) -1;
return( -1 );
}
}
if( flags & SANA2OPF_MINE )
devflags |= FLG_EXCLUSIVE;
if( unit )
{
devflags |= FLG_CLIENT;
intdata.mode |= IM_CLIENT;
}
intdata.SysBase=SysBase; /* Clone SysBase */
/* Start Server Process */
if( !intdata.sigtask )
intdata.sigtask = CreateTask( SERVER_TASK, 15, servertask, 4000);
if( !intdata.sigtask )
{
/* kein Task */
devnode->l.lib_OpenCnt--;
ior->ios2_Req.io_Error = -1;
ior->ios2_Req.io_Device = (struct Device *) -1;
return( -1 );
}
/* Task Setup Done; convert Taglist */
br = AllocMem( 8, MEMF_CLEAR );
if( ti = FindTagItem(S2_CopyToBuff, ior->ios2_BufferManagement) )
br->CopyToBuff = ti->ti_Data;
if( ti = FindTagItem(S2_CopyFromBuff, ior->ios2_BufferManagement) )
br->CopyFromBuff = ti->ti_Data;
if( !br->CopyToBuff || !br->CopyFromBuff )
{
FreeMem( br, 8 );
devnode->l.lib_OpenCnt--;
ior->ios2_Req.io_Error = -1;
ior->ios2_Req.io_Device = (struct Device *) -1;
return( -1 );
}
devnode->l.lib_Flags &= ~LIBF_DELEXP;
ior->ios2_BufferManagement = br;
ior->ios2_Req.io_Unit = (struct Unit *) br;
ior->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
ior->ios2_Req.io_Error = 0;
return( 0 );
}
static long goonline( void )
{
long x;
if( ISOFFLINE )
{
if( x = setupint() )
return( -1 );
devflags &= ~(FLG_OFFLINE | FLG_NOTCONFIGURED);
}
return( 0 );
}
static void gooffline( void )
{
if( ! (ISOFFLINE) )
{
cleanupint();
devflags |= FLG_OFFLINE;
}
}
long __asm __saveds DevExpunge( register __a6 struct MyDev *devnode )
{
long seglist;
struct trackrec *trackrec;
if( devnode->l.lib_OpenCnt )
{
devnode->l.lib_Flags |= LIBF_DELEXP;
return( 0 );
}
gooffline();
if( intdata.sigtask ) RemTask( intdata.sigtask );
if( serverport ) FreeMem( serverport, sizeof(struct MsgPort) );
if( timerport ) FreeMem( timerport, sizeof(struct MsgPort) );
Remove( devnode );
seglist = (long) devnode->seglist;
FreeMem( ((char *) devnode) - devnode->l.lib_NegSize,
devnode->l.lib_PosSize + devnode->l.lib_NegSize );
/* Free tracktype records */
while( ( trackrec = ( struct trackrec * ) RemHead( &tracklist ) ) )
FreeMem( trackrec, sizeof( *trackrec ) );
return( seglist );
}
long __asm __saveds DevClose( register __a1 struct IOSana2Req *ior,
register __a6 struct MyDev *devnode )
{
FreeMem( ior->ios2_Req.io_Unit, 8 );
ior->ios2_Req.io_Device = (struct Device *) -1;
ior->ios2_Req.io_Unit = (struct Unit *) -1;
if( !(--devnode->l.lib_OpenCnt) ) /* ERROR! */
{
devflags &= ~FLG_EXCLUSIVE;
if( devnode->l.lib_Flags & LIBF_DELEXP )
return( DevExpunge(devnode) );
}
return( 0 );
}
void __saveds __asm DevBeginIO( register __a1 struct IOSana2Req *ior )
{
struct Sana2DeviceQuery *devquery;
ior->ios2_Error = IOERR_NOCMD;
switch( ior->ios2_Req.io_Command )
{
case S2_GETSTATIONADDRESS:
ior->ios2_SrcAddr[0] = ior->ios2_DstAddr[0] = (devflags & FLG_CLIENT) ? 1<<7 : 0;
ior->ios2_Error = ior->ios2_WireError = 0;
break;
case S2_TRACKTYPE:
if( addtracktype( ior->ios2_PacketType ) )
{
ior->ios2_Error = S2ERR_BAD_STATE;
ior->ios2_WireError = S2WERR_ALREADY_TRACKED;
}
else
ior->ios2_Error = ior->ios2_WireError = 0;
break;
case S2_UNTRACKTYPE:
if( remtracktype( ior->ios2_PacketType ) )
{
ior->ios2_Error = S2ERR_BAD_STATE;
ior->ios2_WireError = S2WERR_NOT_TRACKED;
}
else
ior->ios2_Error = ior->ios2_WireError = 0;
break;
case S2_GETTYPESTATS:
if( gettrackrec( ior->ios2_PacketType, ior->ios2_StatData ) )
{
ior->ios2_Error = S2ERR_BAD_STATE;
ior->ios2_WireError = S2WERR_NOT_TRACKED;
}
else
ior->ios2_Error = ior->ios2_WireError = 0;
break;
case S2_GETGLOBALSTATS:
memcpy( ior->ios2_StatData, &devstats, sizeof(struct Sana2DeviceStats) );
ior->ios2_Error = ior->ios2_WireError = 0;
break;
case S2_DEVICEQUERY:
ior->ios2_Error = ior->ios2_WireError = 0;
devquery = ior->ios2_StatData;
devquery->DevQueryFormat = devquery->DeviceLevel = 0;
if( devquery->SizeAvailable > 3 ) devquery->AddrFieldSize = 1;
if( devquery->SizeAvailable > 5 ) devquery->MTU = plip_mtu;
if( devquery->SizeAvailable > 9 ) devquery->BPS = plip_bps;
if( devquery->SizeAvailable > 13 ) devquery->HardwareType = PLIP_HWTYPE;
devquery->SizeSupplied = min( devquery->SizeAvailable, 18 );
break;
case S2_ONLINE:
if( goonline() )
ior->ios2_Error = S2ERR_NO_RESOURCES;
else
ior->ios2_Error = ior->ios2_WireError = 0;
break;
case S2_OFFLINE:
gooffline();
ior->ios2_Error = ior->ios2_WireError = 0;
break;
case S2_ONEVENT:
ObtainSemaphore( &eventlistsem );
AddTail( &eventlist, ior );
ReleaseSemaphore( &eventlistsem );
return;
case CMD_READ:
case S2_READORPHAN:
if( ISOFFLINE )
{
ior->ios2_Error = S2ERR_OUTOFSERVICE;
ior->ios2_WireError = S2WERR_UNIT_OFFLINE;
break;
}
PutMsg( serverport, ior );
return;
case CMD_WRITE:
case S2_BROADCAST:
if( ISOFFLINE )
{
ior->ios2_Error = S2ERR_OUTOFSERVICE;
ior->ios2_WireError = S2WERR_UNIT_OFFLINE;
break;
}
if( ior->ios2_DataLength > plip_mtu )
{
ior->ios2_Error = S2ERR_MTU_EXCEEDED;
ior->ios2_WireError = 0;
break;
}
/* 38.10: ios2_Error wird als WriteRetryCounter benutzt */
ior->ios2_Error = 0;
PutMsg( serverport, ior );
return;
case S2_CONFIGINTERFACE:
if( devflags & FLG_NOTCONFIGURED )
{
ior->ios2_SrcAddr[0] = (devflags & FLG_CLIENT) ? (1<<7) : 0;
if( goonline() )
{
ior->ios2_Error = S2ERR_NO_RESOURCES;
ior->ios2_WireError = 0;
}
else
{
ior->ios2_Error = ior->ios2_WireError = 0;
}
break;
}
ior->ios2_Error = S2ERR_SOFTWARE;
ior->ios2_WireError = S2WERR_IS_CONFIGURED;
break;
}
ior->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
return;
}
static long isinlist( struct Node *n, struct List *l )
{
struct Node *cmp = l->lh_Head;
while( cmp != n && cmp->ln_Succ )
cmp = cmp->ln_Succ;
return( cmp == n );
}
long __asm __saveds DevAbortIO( register __a1 struct IOSana2Req *ior )
{
Forbid();
if( isinlist(ior, &eventlist) ||
isinlist(ior, &readlist) ||
isinlist(ior, &readorphanlist) )
{
Remove( ior );
ior->ios2_Error = IOERR_ABORTED;
ior->ios2_WireError = 0;
ReplyMsg( ior );
Permit();
return( 0 );
}
else
{
ObtainSemaphore( &writelistsem );
if( isinlist(ior, &writelist) )
{
Remove( ior );
ReleaseSemaphore( &writelistsem );
ior->ios2_Error = IOERR_ABORTED;
ior->ios2_WireError = 0;
ReplyMsg( ior );
Permit();
return( 0 );
}
ReleaseSemaphore( &writelistsem );
}
Permit();
return( -1 );
}
/* EOF */